<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>贪吃蛇</title>
    <script type="text/javascript" src="./jquery-3.5.1.min.js"></script>
</head>
<!-- 这是一些样式 -->
<style type="text/css">
    #game{
        margin: 5% auto;
    }
    #main{
        /*width: 500px;*/
        /*height: 500px;*/
        background: #c2f3f0;
        position: relative;
        background-image: linear-gradient(45deg, #b3eef0 25%, transparent 0, transparent 75%, #b3eef0 0),
        linear-gradient(45deg, #b3eef0 25%, transparent 0, transparent 75%, #b3eef0 0);
        background-position: 0 0, 25px 25px; background-size: 50px 50px;
    }
    .pbody,#food{
        width: 25px;
        height: 25px;
        background: #eb72a7;
        position: absolute;
    }
    .pbody:last-of-type{
        background: #8a3071;
    }
    @keyframes fade {
        from {
            opacity: 1.0;
        }
        50% {
            opacity: 0.5;
            background: blue;
        }
        to {
            opacity: 0.8;
        }
    }
    #food{
        background: blue;
        animation: fade 2000ms infinite;
    }
    p{
        height: 20px;
        font-size: 18px;
    }
    #scope{
        width: 40px;
        height: 20px;
    }
</style>
<body>
    <!-- 这是主界面 -->
    <div id="game">
        <center>
            <h3>贪吃的蛇</h3>
            <div id="main">
                <!-- <div class="pbody"></div> -->
            </div>
            <p id="msg">按下空格键暂停/继续游戏</p>
            <p>当前得分:
                <span id="score">0</span>
            </p>
            <p>当前阶数:
                <input type="number" id="scope" value="" min="3" max="30" width="100px">
                <button onclick="setScope()">确定</button>
            </p>
        </center>
    </div>
</body>
</html>
<script type="text/javascript">
    // 默认的步长
    const step = 25;
    // 默认的活动范围 
    var scope = parseInt(localStorage.getItem('scope')??20);
    $('#main').css({width:`${scope*step}px`, height:`${scope*step}px`})
    // 多少毫秒刷新
    var time = 400;
    // 默认按下的键盘
    var dir = 39;
    // 默认移动方向
    var prevDir = 39;
    // 蛇的的身子
    var python = [[-25, 0], [0,0],[25, 0]];
    // var python = [[200,0],[200, 25], [200, 50]];
    // 定时器id
    var timing = 0;
    // 用于存储已经占用的坐标 和 未占用的坐标
    var spaceScope = {};
    // 保存所有坐标 作为一个模板
    var baseSpaceScope = {"space":{}, 'pythonBody':{}};
    // 食物坐标
    var foodXY = [];
    // 得分
    var score = 0;

    // 自定义阶数
    if (scope == NaN || scope < 3 || scope > 30) {
        scope = 20;
    }
    // 这行代码没啥用
    $('#scope').val(scope)
    // 初始化所有坐标
    for (var i = 0; i < scope; i++) {
        for (var j = 0; j < scope; j++) {
            let tmpX = j * step, tmpY = i * step;
            baseSpaceScope['space'][tmpX + '_' + tmpY] = [tmpX, tmpY];
        }
    }

    // 移动身子
    moveBody();
    // 创建蛇的身子
    function createPython()
    {
        $('.pbody').remove();
        let pbody = '';
        // 删除对象之间的关联 重新赋值
        spaceScope = JSON.parse(JSON.stringify(baseSpaceScope));
        $.each(python, function(k, v){
            delete spaceScope['space'][v[0] + '_' + v[1]];
            // 已经被蛇占据的格子
            spaceScope['pythonBody'][v[0] + '_' + v[1]] = true;
            pbody += `<div class="pbody" style="left:${v[0]}px; top:${v[1]}px;"></div>`;

        })
        // 当没有食物时创建食物
        if ($('#food').length == 0)
        {
            createFood();
        }
        $('#main').append(pbody);
    }

    // 创建食物
    function createFood()
    {
        let food = Object.values(spaceScope['space']);
        // 通关了
        if (food.length <= 0) {
            success()
            return true;
        }
        // 随机取出一个坐标作为食物
        foodXY = food[Math.floor(Math.random() * food.length)];

        let pbody = `<div id="food" style="left:${foodXY[0]}px; top:${foodXY[1]}px;"></div>`;
        $('#main').html(pbody);
    }

    // 蛇身子移位。尾巴扔到前头
    function moveBody()
    {
        // 当蛇的身体格子个数 与 活动范围格子个数相等时 表示已经通关
        if ($('.pbody').length == (scope * scope)) {
            return true;
        }

        let lastArr = [];
        lastArr[0] = (python[(python.length)-1])[0]
        lastArr[1] = (python[(python.length)-1])[1]


        let y = (lastArr[1]/step);
        let x = (lastArr[0]/step);
        // 选择按键
        switch(dir){
            // 上
            case 38:
                if (y <= 0) {
                    lastArr[1] = (scope * step);
                }
                lastArr[1] = lastArr[1] - step;
            break;
            // 下
            case 40:
                if (y >= (scope - 1)) {
                    lastArr[1] = -step;
                }
                lastArr[1] = lastArr[1] + step;
            break;
            // 左
            case 37:
                if (x <= 0) {
                    lastArr[0] = (scope * step);
                }
                lastArr[0] = lastArr[0] - step;
            break;
            // 右
            case 39:
                if (x >= (scope - 1)) {
                    lastArr[0] = -step;
                }
                lastArr[0] = lastArr[0] + step;
            break;
            default:
            console.log('其他按键')
            break;
        }
        let xy = lastArr[0] + '_'+ lastArr[1];
        if (!$.isEmptyObject(spaceScope) &&  spaceScope['pythonBody'][xy]) {
            $('#msg').html('吃到自己了芭比Q了 赶快调头')
            // 这里游戏就算是结束了
            return false;
        }
        // 吃到食物了
        if (foodXY[0] == lastArr[0] && foodXY[1] == lastArr[1]) {
            $('#food').remove();
            score++;
            $('#score').html(score);
        } else {
            python.splice(0,1);
        }
        python.splice((python.length),0, lastArr);
        createPython();
        prevDir = dir;
    }

    // 游戏刷新
    function start() {
        timing = setInterval(function(){
            moveBody();
        }, time)
    }

    // 游戏通关
    function success() {
        $('#msg').html(`恭喜你完成游戏 得分:${score} 超越了全国99%的人`);
        clearInterval(timing)
        return true;
    }

    // 设置自定义阶数
    function setScope(){
        scope = $('#scope').val()
        if (scope < 3 || scope > 30) {
            scope = 20;
        }
        localStorage.setItem('scope', scope);
        history.go(0);
    }

    $(function(){
        // 键盘按下触发
        $(document).keydown(function(e){
            let thisDir = e.which;
            // 空格键控制暂停与继续
            if (thisDir == 32) {
                if (timing > 0) {
                    clearInterval(timing)
                    timing = 0;
                } else {
                    start()
                }
            }
            // 当前按键与上次按键相反 不执行操作
            if ((thisDir == 38 && prevDir == 40) ||
                (thisDir == 40 && prevDir == 38) ||
                (thisDir == 37 && prevDir == 39) ||
                (thisDir == 39 && prevDir == 37))
            {
                return false;
            }
            if (thisDir == 38 || thisDir == 40 || thisDir == 37 || thisDir == 39){
                dir = thisDir;
                if (timing == 0) {
                    moveBody();
                }
            }
        })
    })
</script>